package jnpf.engine.service;

import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jnpf.base.UserInfo;
import jnpf.engine.custom.cmd.commons.ExpressionCmd;
import jnpf.engine.custom.helper.UserTaskNodeHelper;
import jnpf.engine.entity.FlowTemplateEntity;
import jnpf.engine.entity.FlowTemplateJsonEntity;
import jnpf.engine.enums.FlowNodeTypeEnum;
import jnpf.engine.enums.FlowTaskOperatorEnum;
import jnpf.engine.model.flowengine.shuntjson.childnode.ChildNode;
import jnpf.engine.model.flowengine.shuntjson.childnode.GroupsModel;
import jnpf.engine.model.flowengine.shuntjson.childnode.Properties;
import jnpf.util.JsonUtil;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import lombok.RequiredArgsConstructor;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.*;
import org.flowable.engine.ManagementService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.impl.persistence.entity.ExecutionEntityImpl;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.*;

import static jnpf.engine.custom.constants.GlobalProcessVariableConstants.APPLY_USER_ID;
import static jnpf.engine.util.BpmnModelUtils.getAttributeValueByTaskDefinitionKey;

@Service
@RequiredArgsConstructor
public class FlowableSimulationService {

	private final RepositoryService repositoryService;
	private final ManagementService managementService;
	private final UserTaskNodeHelper userTaskNodeHelper;
	private final FlowTemplateJsonService flowTemplateJsonService;
	private final FlowTemplateService flowTemplateService;
	private final UserProvider userProvider;

	/**
	 * 功能描述：获取模拟流程的流程变量，包含引用的表单
	 * @param flowCode 流程代码
	 * @return {@link Map }<{@link String }, {@link Object }>
	 * @author denglei
	 * @date 2025-02-07
	 */
	public Map<String, Object> simulateVariables(String flowCode) {
		FlowTemplateEntity flowTemplateEntity = flowTemplateService.getOne(Wrappers.lambdaQuery(FlowTemplateEntity.class)
				.eq(FlowTemplateEntity::getEnCode, flowCode)
				.eq(FlowTemplateEntity::getEnabledMark, 1));
		Assert.notNull(flowTemplateEntity, "流程不存在");
		FlowTemplateJsonEntity flowTemplateJsonEntity = flowTemplateJsonService.getOne(Wrappers.lambdaQuery(FlowTemplateJsonEntity.class)
				.eq(FlowTemplateJsonEntity::getTemplateId, flowTemplateEntity.getId())
				.eq(FlowTemplateJsonEntity::getEnabledMark, 1));
		Assert.notNull(flowTemplateJsonEntity, "流程定义不存在");
		String flowTemplateJson = flowTemplateJsonEntity.getFlowTemplateJson();
		ChildNode childNode = JsonUtil.getJsonToBean(flowTemplateJson, ChildNode.class);
		Map<String, Object> map = new LinkedHashMap<>();
		map.put("发起人", new JSONObject().fluentPut("filed", APPLY_USER_ID).fluentPut("dataType", "organizeSelect"));
		traverseChildNodes(childNode, map);
		return map;
	}

	private void traverseChildNodes(ChildNode childNode, Map<String, Object> map) {
		Properties properties = childNode.getProperties();
		//用户节点，如果是采用的表单变量，需要返回
		if (childNode.getType().equals(FlowNodeTypeEnum.APPROVER.getType())) {
			if (FlowTaskOperatorEnum.Variate.getCode().equals(properties.getAssigneeType())) {
				List<Map<String, Object>> formOperates = properties.getFormOperates();
				Map<String, Object> filedMap = formOperates.stream().filter(e -> e.get("id").equals(properties.getFormField())).findFirst().get();
				map.put(filedMap.get("name").toString(), new JSONObject().fluentPut("filed", filedMap.get("jnpfKey")).fluentPut("dataType", filedMap.get("dataType")));
			}
		} else if (childNode.getType().equals(FlowNodeTypeEnum.CONDITION.getType())) {
			properties.getConditions().forEach(e -> {
				List<GroupsModel> groups = e.getGroups();
				groups.forEach(e1 -> {
					map.put(e1.getFieldName(), new JSONObject().fluentPut("filed", e1.getField()).fluentPut("dataType", e1.getJnpfKey()));
				});
			});
		} else if (childNode.getType().equals(FlowNodeTypeEnum.CALL_ACTIVITY.getType())) {
			FlowTemplateJsonEntity flowTemplateJsonEntity = flowTemplateJsonService.getOne(Wrappers.lambdaQuery(FlowTemplateJsonEntity.class)
					.eq(FlowTemplateJsonEntity::getId, properties.getFlowId())
					.eq(FlowTemplateJsonEntity::getEnabledMark, 1));
			Assert.notNull(flowTemplateJsonEntity, "流程定义不存在");
			String flowTemplateJson = flowTemplateJsonEntity.getFlowTemplateJson();
			ChildNode subChildNode = JsonUtil.getJsonToBean(flowTemplateJson, ChildNode.class);
			traverseChildNodes(subChildNode, map);
		}
		if (childNode.getConditionNodes() != null) {
			childNode.getConditionNodes().forEach(e -> traverseChildNodes(e, map));
		}
		if (childNode.getChildNode() != null) {
			traverseChildNodes(childNode.getChildNode(), map);
		}

	}

	/**
	 * 功能描述：模拟流程执行路径，返回执行的节点信息
	 * @param flowCode 流程编码
	 * @param variables 变量
	 * @return {@link Map }<{@link String }, {@link Object }>
	 * @author denglei
	 * @date 2025-02-07
	 */
	public Map<String, Object> simulateProcess(String flowCode, Map<String, Object> variables) {
		FlowTemplateEntity flowTemplateEntity = flowTemplateService.getOne(Wrappers.lambdaQuery(FlowTemplateEntity.class)
				.eq(FlowTemplateEntity::getEnCode, flowCode)
				.eq(FlowTemplateEntity::getEnabledMark, 1));
		Assert.notNull(flowTemplateEntity, "流程不存在");
		FlowTemplateJsonEntity flowTemplateJsonEntity = flowTemplateJsonService.getOne(Wrappers.lambdaQuery(FlowTemplateJsonEntity.class)
				.eq(FlowTemplateJsonEntity::getTemplateId, flowTemplateEntity.getId())
				.eq(FlowTemplateJsonEntity::getEnabledMark, 1));
		Assert.notNull(flowTemplateJsonEntity, "流程定义不存在");
		// 获取流程定义
		ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
				.processDefinitionId(flowTemplateJsonEntity.getProcessDefinitionId())
				.latestVersion()
				.singleResult();
		// 获取 BPMN 模型
		BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
		UserInfo userInfo = userProvider.get();
		String applyUserId = StringUtil.defaultIfBlank(variables.get("applyUserId").toString(), userInfo.getUserId());
		variables.put(APPLY_USER_ID, applyUserId);
		ExecutionEntityImpl execution = new ExecutionEntityImpl();
		execution.setProcessDefinitionId(processDefinition.getId());
		execution.setId("mock");
		variables.forEach((k, v) -> {
			execution.setTransientVariable(k, v);
			execution.setVariable(k, v);
		});
		variables.put("execution", execution);

		// 获取流程的主流程
		Process process = bpmnModel.getMainProcess();

		// 记录执行过的节点信息
		List<Map<String, String>> executedNodes = new ArrayList<>();
		List<String> warnings = new ArrayList<>();

		FlowElement startEvent = process.getFlowElement("startEventId"); // 获取开始事件
		if (startEvent instanceof StartEvent) {
			traverseFlowElements((FlowNode) startEvent, executedNodes, warnings, variables, flowTemplateJsonEntity.getProcessDefinitionId(), process);
		} else {
			warnings.add("流程未定义开始事件");
		}

		// 返回执行路径和警告信息
		Map<String, Object> result = new HashMap<>();
		result.put("executedNodes", executedNodes);
		result.put("warnings", warnings);
		return result;
	}

	/**
	 * 递归遍历流程节点
	 */
	private void traverseFlowElements(FlowNode node, List<Map<String, String>> executedNodes, List<String> warnings, Map<String, Object> variables, String processDefinitionId, Process process) {
		for (SequenceFlow sequenceFlow : node.getOutgoingFlows()) {
			FlowElement nextElement = sequenceFlow.getTargetFlowElement();
			executedNodes.add(createNodeInfo((FlowNode) nextElement, variables, processDefinitionId, process));

			if (nextElement instanceof UserTask) {
				UserTask userTask = (UserTask) nextElement;
				if (userTask.getAssignee() == null && !userTask.getName().equals("流程发起") && userTask.getCandidateUsers().isEmpty() && userTask.getCandidateGroups().isEmpty()) {
					warnings.add("任务 " + userTask.getId() + " 缺少处理人");
				}
			}

			if (nextElement instanceof ExclusiveGateway) {
				ExclusiveGateway exclusiveGateway = (ExclusiveGateway) nextElement;
				boolean matched = false;
				for (SequenceFlow outgoingFlow : exclusiveGateway.getOutgoingFlows()) {
					if (evaluateCondition(outgoingFlow, variables)) {
						traverseFlowElements((FlowNode) outgoingFlow.getTargetFlowElement(), executedNodes, warnings, variables, processDefinitionId, process);
						matched = true;
						break;
					}
				}
				if (!matched) {
					warnings.add("网关 " + exclusiveGateway.getId() + " 没有匹配的路径");
				}
			} else if (nextElement instanceof FlowNode) {
				FlowNode nextNode = (FlowNode) nextElement;
				traverseFlowElements(nextNode, executedNodes, warnings, variables, processDefinitionId, process);
			}
		}
	}

	/**
	 * 解析 Flowable 网关条件表达式
	 */
	public boolean evaluateCondition(SequenceFlow sequenceFlow, Map<String, Object> variables) {
		String conditionExpression = sequenceFlow.getConditionExpression();
		if (conditionExpression == null || conditionExpression.isEmpty()) {
			return true;
		}
		return managementService.executeCommand(new ExpressionCmd(null, conditionExpression, variables));
	}

	/**
	 * 创建节点信息
	 */
	private Map<String, String> createNodeInfo(FlowNode node, Map<String, Object> variables, String processDefinitionId, Process process) {
		Map<String, String> nodeInfo = new LinkedHashMap<>();
		nodeInfo.put("id", node.getId());
		nodeInfo.put("name", node.getName());
		if (node instanceof UserTask) {
			UserTask userTask = (UserTask) node;
			String property = getAttributeValueByTaskDefinitionKey(process, userTask.getId(), "userTask");
			Properties properties = JSONObject.parseObject(property, new TypeReference<Properties>() {
			});
			LambdaQueryWrapper<FlowTemplateJsonEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
			lambdaQueryWrapper.eq(FlowTemplateJsonEntity::getProcessDefinitionId, processDefinitionId);
			lambdaQueryWrapper.select(FlowTemplateJsonEntity::getTemplateId);
			FlowTemplateJsonEntity templateJsonEntity = flowTemplateJsonService.getOne(lambdaQueryWrapper);

			HashMap<String, String> taskInfoMap = MapUtil.newHashMap();
			taskInfoMap.put("processDefinitionId", processDefinitionId);

			taskInfoMap.put("taskDefinitionKey", userTask.getId());
			taskInfoMap.put(APPLY_USER_ID, MapUtil.getStr(variables, APPLY_USER_ID));
			List<String> assignUserList = userTaskNodeHelper.getAssignUserList(properties, taskInfoMap, templateJsonEntity.getTemplateId(), variables);
			nodeInfo.put("assignee", userTask.getAssignee() != null ? String.join(",", assignUserList) : "未分配");
		}


		return nodeInfo;
	}


	public String getFlowTemplateJson(String flowCode) {
		FlowTemplateEntity flowTemplateEntity = flowTemplateService.getOne(Wrappers.lambdaQuery(FlowTemplateEntity.class)
				.eq(FlowTemplateEntity::getEnCode, flowCode)
				.eq(FlowTemplateEntity::getEnabledMark, 1));
		Assert.notNull(flowTemplateEntity, "流程不存在");
		FlowTemplateJsonEntity flowTemplateJsonEntity = flowTemplateJsonService.getOne(Wrappers.lambdaQuery(FlowTemplateJsonEntity.class)
				.eq(FlowTemplateJsonEntity::getTemplateId, flowTemplateEntity.getId())
				.eq(FlowTemplateJsonEntity::getEnabledMark, 1));
		Assert.notNull(flowTemplateJsonEntity, "流程定义不存在");
		return flowTemplateJsonEntity.getFlowTemplateJson();
	}
}
